package com.tsj.spzx.product.service.Impl;

import com.alibaba.fastjson.JSON;
import com.tsj.spzx.model.entity.product.Category;
import com.tsj.spzx.product.mapper.CategoryMapper;
import com.tsj.spzx.product.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 查询所有一级分类
     * @return
     *
     * 在此，我们需要使用缓存技术，因为像分类这些东西，变化不会很大，每次都从数据库中查询会造成数据库压力，所以，我们可以见这些不常改变的数据缓存至redis中，
     *      *      这样，下次再查询的时候，直接从redis中查询，这样，数据库压力会减小，并且，查询速度也会提高。
     *      * 法一：使用RedisTemplate
     *      * 法二：使用SpringCache 注解
     * 使用缓存后，还会造成一些情况，当我们修改了数据时，缓存并不会修改，解决办法如下：
     *      1、高频更新数据：
     *          使用@CachePut注解加载更新方法上，会依据自动更新缓存中的内容，
     *          或者使用手动管理缓存，每次执行更新方法后，手动删除缓存
     *      2、低频更新数据：
     *          使用@CacheEvict注解加在更新方法上，删除缓存
     *      3、设置缓存的存活时间
     */
    @Override
    public List<Category> findOneCategory() {       // 法一：使用RedisTemplate
        // 1、首先判断redis中有没有缓存
        String categoryListOneStr = redisTemplate.opsForValue().get("category:one");
        if (StringUtils.hasText(categoryListOneStr)){
            // 存在数据，解析为List集合
            List<Category> categoryList = JSON.parseArray(categoryListOneStr, Category.class);
            log.info("从Redis缓存中查询到了所有的一级分类数据");
            return categoryList;
        }

        // 2、如果不存在，则查询数据库，并且将数据缓存到redis中
        List<Category> categoryList = categoryMapper.findOneCategory();
        log.info("从数据库中查询到了所有的一级分类数据");
        redisTemplate.opsForValue().
                set("category:one", JSON.toJSONString(categoryList), 7, TimeUnit.DAYS);
        return categoryList;
    }

    /**
     * 查询分类,返回树形结构格式
     * @return
     */
    @Cacheable(value = "category", key = "'tree'")  // key的最终结果是 category::tree
    @Override
    public List<Category> findCategoryTree() {      // 法二：使用SpringCache 注解

        // 准备一个集合，封装最后要返回的数据
        List<Category> categoryTreeList = new ArrayList<>();

        // 先查询所有节点
        List<Category> categoryList = categoryMapper.findCategoryTree();
        // 遍历所有节点，找到所有一级节点
        for (Category category : categoryList) {
            if (category.getParentId() == 0){
               categoryTreeList.add(findChildren(category, categoryList));
            }
        }
        return categoryTreeList;
    }
    // 寻找子节点
    public Category findChildren(Category category, List<Category> categoryList) {
        category.setChildren(new ArrayList<>());

        for (Category category1 : categoryList) {
            if (category1.getParentId().equals(category.getId())){
                category.getChildren().add(findChildren(category1, categoryList));
            }
        }
        return category;
    }

}
